----------------------------------------------------------------------------------
-- Company: 
-- Engineer: Antti Lukats 
-- 
-- Create Date:    12:11:29 09/06/2007 
-- Design Name: 
-- Module Name:    top - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.02 - Modified by David Rorex to include both input & output
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity top is Port ( 
	-- Cart Slot
	PHI	: in  STD_LOGIC;
	CS   	: in  STD_LOGIC;
	RD   	: in  STD_LOGIC;
	WR   	: in  STD_LOGIC;
	REQ  	: out STD_LOGIC;
	AD   	: inout  STD_LOGIC_VECTOR (7 downto 0); -- 8 bit of AD bus only !
	
	-- Sipsik Slot 8 Pins = 6 IO's 
        XA	: inout  STD_LOGIC_VECTOR (5 downto 0);
	-- Sipsik Slot 8 Pins = 6 IO's + VCC as I/O!
	XB	: inout  STD_LOGIC_VECTOR (5 downto 0);
        VCCB    : inout  STD_LOGIC
	);
end top;

architecture Behavioral of top is

--
--
--
signal CART_CLK: STD_LOGIC; -- Clock retrived from RD/WR
--
-- ROM Bank CS
--
signal CS_ADDR: STD_LOGIC_VECTOR (7 downto 0);
signal CS_WRBUS: STD_LOGIC_VECTOR (7 downto 0);
signal CS_RDBUS: STD_LOGIC_VECTOR (7 downto 0);

signal REGA: STD_LOGIC_VECTOR (5 downto 0) := "000000";
signal REGB: STD_LOGIC_VECTOR (5 downto 0) := "000000";

-- data direction register
-- if a bit is '1' then output on that pin
-- else input on that pin
signal DDRA: std_logic_vector (5 downto 0) := "000000";
signal DDRB: std_logic_vector (5 downto 0) := "000000";

begin
	-- CART
	REQ <= '0';
	CS_WRBUS 	<= AD(7 downto 0);
	AD(7 downto 0) 	<= CS_RDBUS when (CS='0' and RD='0') else "ZZZZZZZZ";


        -- Simple GPIO

	process (WR, AD)
	begin
		if (rising_edge(WR)) then
                        if (CS='0') then
                            -- if writing to address 0
                            -- then store data for outputting on XA
                            if(CS_ADDR = "00000000") then
                                REGA <= CS_WRBUS(5 downto 0);
                            -- if writing to address 2
                            -- store the DDRA
                            elsif(CS_ADDR = "00000010") then
                                DDRA <= CS_WRBUS(5 downto 0);
                            end if;
                            -- if writing to address 4
                            -- then store data for outputting on XB
                            if(CS_ADDR = "00000100") then
                                REGB <= CS_WRBUS(5 downto 0);
                            -- if writing to address 8
                            -- store the DDRB
                            elsif(CS_ADDR = "00001000") then
                                DDRB <= CS_WRBUS(5 downto 0);
                            end if;
                        end if;
		end if;
	end process;

        -- latch address
        process (CS, AD)
        begin
            if (CS='1') then
                CS_ADDR <= AD;
            end if;
        end process;

        -- output on XA, only if DDR is set for each pin
        XA(0) <= REGA(0) when (DDRA(0) = '1') else 'Z'; 
        XA(1) <= REGA(1) when (DDRA(1) = '1') else 'Z'; 
        XA(2) <= REGA(2) when (DDRA(2) = '1') else 'Z'; 
        XA(3) <= REGA(3) when (DDRA(3) = '1') else 'Z'; 
        XA(4) <= REGA(4) when (DDRA(4) = '1') else 'Z'; 
        XA(5) <= REGA(5) when (DDRA(5) = '1') else 'Z'; 

        -- output on XB, only if DDR is set for each pin
        XB(0) <= REGB(0) when (DDRB(0) = '1') else 'Z'; 
        XB(1) <= REGB(1) when (DDRB(1) = '1') else 'Z'; 
        XB(2) <= REGB(2) when (DDRB(2) = '1') else 'Z'; 
        XB(3) <= REGB(3) when (DDRB(3) = '1') else 'Z'; 
        XB(4) <= REGB(4) when (DDRB(4) = '1') else 'Z'; 
        XB(5) <= REGB(5) when (DDRB(5) = '1') else 'Z'; 

        -- When reading from GBA slot
        process(XA, DDRA, XB, DDRB, CS_RDBUS, CS_ADDR)
        begin
            case (CS_ADDR) is
                when "00000000" => -- address 0, read the XA pins
                    CS_RDBUS <= "00" & XA;
                when "00000010" => -- address 2, read the current DDRA value
                    CS_RDBUS <= "00" & DDRA;
                when "00000100" => -- address 4, read the XB pins
                    CS_RDBUS <= "00" & XB;
                when "00001000" => -- address 8, read the current DDRB value
                    CS_RDBUS <= "00" & DDRB;
                when others => -- else return 0xff
                    CS_RDBUS <= "11111111";
            end case;
        end process;

        
        VCCB <= '1';
        
end Behavioral;

